/**
 * JAVACC DEMO 1.0
 * @copy right dwusoft company All rights reserved. 
 * @Package com.apache.uct.common.filter  
 */
package com.apache.uct.common.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.apache.api.manager.ProxyManager;
import com.apache.api.vo.ParamsVo;
import com.apache.database.constant.SpringContextLoader;
import com.apache.database.constant.SystemTools;
import com.apache.passport.common.PassPortConst;
import com.apache.passport.common.PassportHelper;
import com.apache.passport.common.XmlWhiteUtils;
import com.apache.passport.entity.Token;
import com.apache.rpc.util.DesUtils;
import com.apache.tools.StrUtil;
import com.apache.uct.common.LoginUser;
import com.apache.uct.common.ToolsUtil;
import com.apache.uct.common.entity.Act;
import com.apache.uct.common.entity.Role;
import com.apache.uct.service.plugins.ActCacheHelper;

/**
 * description:  自定义拦截器,拦截action,do等权限控制的地址(单点与uct集成时使用)
 * @author Hou Dayu 创建时间：2016-2-3  
 */
public class SsoServerFilter implements Filter {

	private Logger log = Logger.getLogger(SsoServerFilter.class);

	private String COOKIENAME = "";
	//自定义登录页面
	private String login_url = "";
	//白名单
	private String white_url = "";
	//访问未授权地址,跳转url
	private String jumpUrl = "";
	// rpc服务地址,引入此属性,主要是因为加密统一
	private String rpc_service_url = "";

	private ProxyManager uctProxyManager;

	private Map<String, String> unLockMap = new HashMap<String, String>();

	private Map<String, ArrayList<String>> whiteMap = new HashMap<String, ArrayList<String>>();
	private String errorPage = "";

	/**
	 * TODO 简单描述该方法的实现功能（可选）.  
	 */
	public void init(FilterConfig arg0) throws ServletException {
		COOKIENAME = SystemTools.getInstance().getValue("cookieName");
		//自定义登录页面
		login_url = SystemTools.getInstance().getValue("login.url");
		//白名单
		white_url = SystemTools.getInstance().getValue("white.url");
		//访问未授权地址,跳转url
		jumpUrl = SystemTools.getInstance().getValue("jump.url");
		rpc_service_url = SystemTools.getInstance().getValue("rpc_service_url");

		uctProxyManager = (ProxyManager) SpringContextLoader.getBean("uctProxyManager");

		//初始化uct服务端 白名单配置
		unLockMap.put("/common/image.jsp", "");
		unLockMap.put("/uct/service/", "");
		unLockMap.put("/passport/outside", "");
		unLockMap.put("/login.jsp", "");
		unLockMap.put("/mobile/service", "");
		unLockMap.put("/error.action", "");
		//unLockMap.put("/index.action", "");
		//错误页面地址
		errorPage = StrUtil.doNull(arg0.getInitParameter("errorPage"), "/");
	}

	/**
	 * TODO 自定义拦截器,服务端不适用white.xml,其只为客户端提供配置服务
	 *   	过滤url
	 *   	过滤用户
	 *   	过滤url后缀
	 *   	过滤css.js.等
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)  
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
			ServletException {

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		resp.setCharacterEncoding("UTF-8");
		resp.setDateHeader("expires", 0);
		resp.setHeader("Cache-Control", "no-cache");
		resp.setHeader("pragma", "no-cache");
		req.setCharacterEncoding("UTF-8");
		//CookeHeader(resp, req);
		//判断是否为外部系统登录
		String sysEname = request.getParameter("sys");
		String setCookieUrl = request.getParameter("cset");
		String goUrl = request.getParameter("go");
		String clientId = request.getParameter("_client");
		String ptlang = request.getParameter("ptlang");

		//获取uri信息
		String uri = req.getRequestURI();
		//获取访问路径
		String servletPath = req.getServletPath();
		//获取后缀名
		String suffix = PassportHelper.getInstance().parseUrlSuffix(uri);
		//后缀名小写
		suffix = suffix.toLowerCase();

		//如果存在后缀为图片,css等格式,直接跳过,不拦截
		if (StrUtil.isNotNull(suffix)) {
			if (PassPortConst.SUFFIX.contains(suffix)) {
				chain.doFilter(req, resp);
				return;
			}
		}
		//获取token
		String tokenCookie = PassportHelper.getInstance().getCurrCookie(req);
		//获取ucsso
		String ucsso = PassportHelper.getInstance().getCurrCookie(req, "_uc.sso");

		//2015年2月4日11:07:24 更新 如果客户端根据token访问获取,如果不存在值,则从request中取值
		String pkt = req.getParameter("tokenId");
		if (!StrUtil.isNull(pkt)) {//第三方系统或客户端
			outwardSys(goUrl, pkt, setCookieUrl, ptlang, req, resp);
			return;
		}
		Token token = (Token) SystemTools.getInstance().getCache("loginToken").getCacheCloneByKey(tokenCookie);

		if (ToolsUtil.isEmpty(token)) {//白名单处理
			if (actPathGoto(req)) {
				chain.doFilter(request, response);
				return;
			}
		} else {
			if ((!ToolsUtil.isNull(sysEname) && !ToolsUtil.isNull(setCookieUrl) && !ToolsUtil.isNull(goUrl) && !ToolsUtil
					.isNull(clientId))) {
				//获取tokenId,然后跳进连入地址
				req.setAttribute("tokenId", token.getTokenId());
				resp.sendRedirect(setCookieUrl + "?ticket=" + token.getTokenId() + "&go=" + goUrl + "&ucsso=" + ucsso);
				return;
			} else {
				String desEname = token.getUserEname();
				LoginUser loginUser = initLoginUser(req, resp, tokenCookie, desEname);
				if (actPathGoto(req)) {
					chain.doFilter(request, response);
					return;
				}
				String onlyLoginUrl = ToolsUtil.getInstance().getValueByKey("unity_noright_url");
				if (ToolsUtil.isNotNull(onlyLoginUrl)) {
					String[] wus = onlyLoginUrl.split(",");
					for (int i = 0; i < wus.length; i++) {
						String wurl = wus[i];
						if (ToolsUtil.isNotNull(wurl)) {
							if (servletPath.startsWith(wurl)) {
								chain.doFilter(request, response);
								return;
							}
						}
					}
				}
				String ctxpath = req.getContextPath();
				if ("1".equals(SystemTools.getInstance().getValue("usage_patterns"))) {
					if (!canAccess(loginUser, servletPath)) {//验证访问权限
						req.getSession().setAttribute("errorMsg", "对不起,您没有访问权限!!");
						resp.sendRedirect(ctxpath + errorPage);
						log.error("没有操作权限");
						return;
					}
				}
				chain.doFilter(request, response);
				return;
			}
		}
		//如果不存在.则跳转其他页面,默认为登录页面
		resp.sendRedirect(login_url);
	}

	private boolean actPathGoto(HttpServletRequest request) {
		String servletPath = request.getServletPath();
		Iterator<String> it = unLockMap.keySet().iterator();
		while (it.hasNext()) {
			String url = it.next();
			if (servletPath.indexOf(url) > -1) {
				return true;
			}
		}
		if (white_url.contains(servletPath)) {
			return true;
		}
		//白名单处理
		if (unlockPath(servletPath)) {
			return true;
		}
		return false;
	}

	/**
	 * description:  外部系统调用
	 */
	private void outwardSys(String goUrl, String pkt, String setCookieUrl, String ptlang, HttpServletRequest req,
			HttpServletResponse resp) throws IOException, ServletException {
		Token token = (Token) SystemTools.getInstance().getCache("loginToken").getCacheCloneByKey(pkt);
		//如果为空,则让其跳转到客户端系统进行登录
		if (ToolsUtil.isEmpty(token)) {
			resp.sendRedirect(ToolsUtil.isNull(goUrl) ? login_url : goUrl);
			return;
		}
		//只处理客户端请求,加此判断主要用于passport系统使用tokenId登录时,防止误入此方法
		if ((!ToolsUtil.isNull(pkt) && !ToolsUtil.isNull(goUrl))) {
			//ptlang
			ArrayList<String> lst = new ArrayList<String>();
			lst.add(rpc_service_url);
			lst.add(pkt);
			lst.add(setCookieUrl);
			lst.add(goUrl);
			lst.add("apache");
			Collections.sort(lst);
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < lst.size(); ++i) {
				sb.append((String) lst.get(i));
			}
			String ptlangSha1 = PassportHelper.getInstance().SHA1(sb.toString());
			log.debug("rpc_url msg:[{}]" + rpc_service_url);
			log.debug("pkt msg:[{}]" + pkt);
			log.debug("setCookieUrl msg:[{}]" + setCookieUrl);
			log.debug("goUrl msg:[{}]" + goUrl);
			log.debug("ptlangSha1=" + ptlangSha1 + "; ptlang=" + ptlang);

			if (ptlangSha1.equals(ptlang)) {
				Cookie ticket = new Cookie(COOKIENAME, pkt);
				ticket.setPath("/");
				ticket.setMaxAge(-1);
				resp.addCookie(ticket);

				Cookie ucss = new Cookie("_uc.sso", token.getUserEname());
				ucss.setPath("/");
				ucss.setMaxAge(-1);
				resp.addCookie(ucss);
				req.setAttribute("tokenId", token.getTokenId());
				resp.sendRedirect(setCookieUrl + "/cset" + "?ticket=" + token.getTokenId() + "&go=" + goUrl + "&ucsso="
						+ token.getUserEname());
			} else {
				log.debug("passport msg:[{}]=Keys Are Different");
				req.getRequestDispatcher(jumpUrl).forward(req, resp);
			}
			return;
		} else {
			Cookie ticket = new Cookie(COOKIENAME, pkt);
			ticket.setPath("/");
			ticket.setMaxAge(-1);
			resp.addCookie(ticket);

			Cookie ucss = new Cookie("_uc.sso", token.getUserEname());
			ucss.setPath("/");
			ucss.setMaxAge(-1);
			resp.addCookie(ucss);
			req.setAttribute("tokenId", token.getTokenId());
		}
	}

	/**
	 * description:  获取loginUser信息
	 */
	private LoginUser initLoginUser(HttpServletRequest request, HttpServletResponse response, String cookieValue,
			String loginName) {
		LoginUser loginUser = null;
		if (ToolsUtil.isNotNull(cookieValue)) {
			loginUser = (LoginUser) request.getSession().getAttribute("loginUser");//从session中获取用户对象
			if (ToolsUtil.isEmpty(loginUser)) {
				String value = DesUtils.getInstance().decrypt(loginName);
				if (ToolsUtil.isNotNull(value)) {
					ParamsVo vo = new ParamsVo();
					vo.setParams("userEname", value);
					vo.setKey("loginUser");
					loginUser = (LoginUser) uctProxyManager.doInvoke(vo);
					if (!ToolsUtil.isEmpty(loginUser)) {
						request.getSession().setAttribute("loginUser", loginUser);
						request.getSession().setAttribute("sysUser", loginUser.getSysFlag());
						if (ToolsUtil.isEmpty(request.getSession().getAttribute("loginUserRoles"))) {
							List<Role> roles = ActCacheHelper.getInstance().getRolesForUserEname(
									loginUser.getUserEname());//获取用户角色列表
							if (ToolsUtil.isEmpty(roles)) {
								request.getSession().setAttribute("loginUserRoles", roles);
							}
						}
					}
				}
			}
		}
		return loginUser;
	}

	/**
	 * description:  白名单判断
	 */
	private boolean unlockPath(String path) {
		XmlWhiteUtils.getInstance().deWhiteXml(whiteMap);
		ArrayList<String> whiteUrl = (ArrayList<String>) whiteMap.get("whiteUrl");
		ArrayList<String> whiteParadigm = (ArrayList<String>) whiteMap.get("whiteParadigm");
		int wp = whiteParadigm.size();
		if (path.length() > 1) {
			if (whiteUrl.contains(path)) {
				return true;
			}
			for (int i = 0; i < wp; i++) {
				if (((String) whiteParadigm.get(i)).contains("*")) {
					String wdir = ((String) whiteParadigm.get(i)).replace("*", "");
					int s = path.indexOf(wdir);
					if (s == 0) {
						return true;
					}
				} else if (!"".equals(whiteParadigm.get(i))) {
					int s = path.indexOf((String) whiteParadigm.get(i));
					if (s == 0) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * description:  权限验证
	 */
	private boolean canAccess(LoginUser loginUser, String path) {
		boolean mark = false;
		if (loginUser.getUserEname().equals(
				StrUtil.doNull(SystemTools.getInstance().getValue("uct_supper_user"), "admin"))) {
			return true;
		}
		Map<String, Act> acts = loginUser.getActMap();
		if (null != acts && !acts.isEmpty()) {
			for (String key : acts.keySet()) {
				Act act = acts.get(key);
				if (StrUtil.isNotNull(act.getActUrl())) {
					String str[] = act.getActUrl().split(",");
					for (int i = 0; i < str.length; i++) {
						if (str[i].endsWith(".action")) {
							if (path.equals(str[i]))
								return true;
						} else if (path.startsWith(str[i])) {
							return true;
						}
					}
				}
			}
		}
		return mark;
	}

	/**
	 * TODO 简单描述该方法的实现功能（可选）.  
	 */
	public void destroy() {
	}
}
